#pragma once

#ifdef _WIN32
#ifdef ASYNCLIB_EXPORTS
#define ASYNCLIB_API __declspec(dllexport)
#else
#define ASYNCLIB_API __declspec(dllimport)
#endif
#else
#define ASYNCLIB_API __attribute__((visibility("default")))
#endif

typedef unsigned long DWORD;
typedef unsigned int  UINT;
typedef long long     INT64;

#ifdef _WIN32
typedef void *        HANDLE;
#else
typedef int           HANDLE;
#endif

namespace AsyncLib
{

struct ATID
{
public:
	constexpr explicit ATID(intptr_t value) : m_value(value)
	{
	}

	constexpr operator intptr_t() const
	{
		return m_value;
	}

private:
	intptr_t m_value;
};

constexpr ATID ATID_TP (-1);
constexpr ATID ATID_NULL(0);
constexpr ATID ATID_MAIN(1);

class ITimerTask
{
public:
	virtual ~ITimerTask() = default;
	virtual void Start(UINT nElapse) = 0;
	virtual void Stop() = 0;
	virtual void Close() = 0;

	void SetCallback(std::function<void()>&& fnCallback)
	{
		m_fnCallback = std::move(fnCallback);
	}

	void DoCallback() const
	{
		if (m_fnCallback)
			m_fnCallback();
	}

private:
	std::function<void()> m_fnCallback;
};

class IFileTask
{
public:
	virtual ~IFileTask() = default;
	virtual void Read(void *lpBuffer, INT64 nOffset, UINT nBytesToRead, std::function<void(UINT, DWORD)>&& fnCallback) = 0;
	virtual void Write(const void *lpBuffer, INT64 nOffset, UINT nBytesToWrite, std::function<void(UINT, DWORD)>&& fnCallback) = 0;
	virtual void Close() = 0;
};

class IAsyncLib
{
public:
	virtual void Init(ATID atidMax) = 0;
	virtual void Exit(bool bWaitTasks) = 0;

	virtual void PostTask(ATID atid, std::function<void()>&& fnTask) = 0;
	virtual void PostDelayedTask(UINT nMilliseconds, std::function<void()>&& fnTask) = 0;
	virtual void WaitForAsync(HANDLE handle, UINT nMilliseconds, std::function<void(DWORD)>&& fnCallback) = 0;

	virtual bool IsInTaskThread(ATID atid) const = 0;
	virtual bool IsInThreadPool() const = 0;

	virtual std::shared_ptr<ITimerTask> CreateTimerTask(bool bUITimer) = 0;
	virtual std::shared_ptr<IFileTask> CreateFileTask(HANDLE hFile) = 0;
};

ASYNCLIB_API IAsyncLib& GetAsyncLib();

} // namespace AsyncLib
